              <div align="right">
${TARGET="offline"}                <a href="${LDAP_SDK_HOME_URL}" style="font-size: 85%">LDAP SDK Home Page</a>
                <br>
                <a href="${BASE}index.${EXTENSION}" style="font-size: 85%">Product Information</a>
                <br>
                <a href="index.${EXTENSION}" style="font-size: 85%">Getting Started with the LDAP SDK</a>
              </div>

              <h2>Using Standard Extended Operations</h2>

              <p>
                Extended operations allow directory servers to perform processing which isn't
                defined as part of the core LDAP specification.  They provide a means of allowing
                directory servers to provide enhanced functionality.
              <p>

              <p></p>
              <h3>The Cancel Extended Operation</h3>

              <p>
                The cancel extended operation is defined in RFC 3909, and it is similar to the
                standard LDAP abandon operation in that it can be used to request that the server
                stop processing another operation.  However, whereas the abandon request does not
                have a response, and an operation which gets abandoned may never receive a response
                from the server, the cancel extended operation does have a response, which allows
                it to receive the result of the cancel operation and also ensures that any
                operation which is canceled will be sent a result indicating that it has been
                canceled.
              </p>

              <p>
                Whenever the server processes a cancel request, it should include one of the
                following result codes in the response:
              </p>

              <ul>
                <li>
                  <tt>CANCELED</tt> -- Indicates that the operation was successfully canceled.
                  <br><br>
                </li>

                <li>
                  <tt>NO_SUCH_OPERATION</tt> -- Indicates that the server was not able to find the
                  target operation (e.g., because it had already completed).
                  <br><br>
                </li>

                <li>
                  <tt>TOO_LATE</tt> -- Indicates that the client request was received too late and
                  the server processing is past the point at which the request can be canceled.
                  <br><br>
                </li>

                <li>
                  <tt>CANNOT_CANCEL</tt> -- Indicates that the associated operation is one that
                  cannot be canceled.  Abandon, bind, and unbind requests cannot be canceled, and
                  neither can cancel or StartTLS extended operations.
                  <br><br>
                </li>
              </ul>

              <p>
                Note that cancel requests are only available for use with operations that are being
                processed asynchronously.  See the <A HREF="asynchronous.${EXTENSION}">Processing
                Asynchronous Operations</A> page for more information.
              </p>

              <p>
                The following example initiates an asynchronous modify operation and then
                attempts to cancel it:
              </p>

              <pre>
Modification mod = new Modification(ModificationType.REPLACE,
     "description", "This is the new description.");
ModifyRequest modifyRequest =
     new ModifyRequest("dc=example,dc=com", mod);

AsyncRequestID asyncRequestID =
     connection.asyncModify(modifyRequest, myAsyncResultListener);

// Assume that we've waited a reasonable amount of time but the modify
// hasn't completed yet so we'll try to cancel it.

ExtendedResult cancelResult;
try
{
  cancelResult = connection.processExtendedOperation(
       new CancelExtendedRequest(asyncRequestID));
  // This doesn't necessarily mean that the operation was successful, since
  // some kinds of extended operations (like cancel) return non-success
  // results under normal conditions.
}
catch (LDAPException le)
{
  // For an extended operation, this generally means that a problem was
  // encountered while trying to send the request or read the result.
  cancelResult = new ExtendedResult(le.toLDAPResult());
}

switch (cancelResult.getResultCode().intValue())
{
  case ResultCode.CANCELED_INT_VALUE:
    // The modify operation was successfully canceled.
    break;
  case ResultCode.CANNOT_CANCEL_INT_VALUE:
    // This indicates that the server isn't capable of canceling that
    // type of operation.  This probably won't happen for  this kind of
    // modify operation, but it could happen for other kinds of operations.
    break;
  case ResultCode.TOO_LATE_INT_VALUE:
    // This indicates that the cancel request was received too late and the
    // server is intending to process the operation.
    break;
  case ResultCode.NO_SUCH_OPERATION_INT_VALUE:
    // This indicates that the server doesn't know anything about the
    // operation, most likely because it has already completed.
    break;
  default:
    // This suggests that the operation failed for some other reason.
    break;
}
</pre>

              <p></p>
              <h3>The Password Modify Extended Operation</h3>

              <p>
                The password modify extended operation is defined in RFC 3062 and can be used to
                change the password for a given user.  It provides the ability to specify the
                user's current password for validation purposes, and also provides the ability to
                request (by not including a new password value) that the server generate a new
                password on the user's behalf (in which case the new password will be made
                available through the <tt>getGeneratedPassword</tt>,
                <tt>getGeneratedPasswordBytes</tt>, and <tt>getRawGeneratedPassword</tt> methods of
                the corresponding <tt>PasswordModifyExtendedResult</tt> object).
              </p>

              <p>
                The password modify extended request also provides a mechanism to identify the user
                for which to change the password.  If this is not provided, then it will change the
                password for the currently-authenticated user.  If it is provided, then the
                specification is a little unclear as to the format of the value (in particular,
                it says that the userIdentity field may or may not be an LDAP DN), but server
                implementations generally support specifying the target userIdentity value as a DN,
                and many also support specifying it as an authorization ID.
              </p>

              <p>
                The following example demonstrates the use of the password modify extended
                operation to change the password for user
                "uid=test.user,ou=People,dc=example,dc=com" and have the server generate a new
                password for that user.
              </p>

              <pre>
PasswordModifyExtendedRequest passwordModifyRequest =
     new PasswordModifyExtendedRequest(
          "uid=test.user,ou=People,dc=example,dc=com", // The user to update
          (String) null, // The current password for the user.
          (String) null); // The new password.  null = server will generate

PasswordModifyExtendedResult passwordModifyResult;
try
{
  passwordModifyResult = (PasswordModifyExtendedResult)
       connection.processExtendedOperation(passwordModifyRequest);
  // This doesn't necessarily mean that the operation was successful, since
  // some kinds of extended operations return non-success results under
  // normal conditions.
}
catch (LDAPException le)
{
  // For an extended operation, this generally means that a problem was
  // encountered while trying to send the request or read the result.
  passwordModifyResult = new PasswordModifyExtendedResult(
       new ExtendedResult(le.toLDAPResult()));
}

LDAPTestUtils.assertResultCodeEquals(passwordModifyResult,
     ResultCode.SUCCESS);
String serverGeneratedNewPassword =
     passwordModifyResult.getGeneratedPassword();
</pre>

              <p></p>
              <h3>The StartTLS Extended Operation</h3>

              <p>
                The StartTLS extended operation is defined in RFC 4511 and may be used to initiate
                a secure communication channel over a previously unencrypted connection.  That is,
                it provides the option of allowing the server to perform both clear-text and secure
                communication over a single port so that it is not necessary to expose separate
                ports for clear-text and encrypted communication.
              </p>

              <p>
                The requirements for communicating with a directory server using a
                StartTLS-encrypted channel are essentially the same as those for establishing an
                SSL-based connection as described in the <A HREF="connections.${EXTENSION}">Creating and
                Using LDAP Connections</A> section.  You can either use the default SSL context
                provided by the JVM or specify your own context.  In most cases, you will want to
                use the latter, as it provides greater flexibility and more options for determining
                whether to trust the server certificate.  And as with creating SSL-based
                connections, the <tt>com.unboundid.util.TrustAllSSLSocketFactory</tt> can be used
                to request that the client blindly trust whatever certificate the server presents.
              </p>

              <p>
                The following code demonstrates the process for using the StartTLS extended
                operation, using a trust store file to determine whether to trust the certificate
                presented by the server:
              </p>

              <pre>
// Create an SSLContext that will be used to perform the cryptographic
// processing.
SSLUtil sslUtil = new SSLUtil(new TrustStoreTrustManager(trustStorePath));
SSLContext sslContext = sslUtil.createSSLContext();

 // Create and process the extended request to secure a connection.
StartTLSExtendedRequest startTLSRequest =
     new StartTLSExtendedRequest(sslContext);
ExtendedResult startTLSResult;
try
{
  startTLSResult = connection.processExtendedOperation(startTLSRequest);
  // This doesn't necessarily mean that the operation was successful, since
  // some kinds of extended operations return non-success results under
  // normal conditions.
}
catch (LDAPException le)
{
  // For an extended operation, this generally means that a problem was
  // encountered while trying to send the request or read the result.
  startTLSResult = new ExtendedResult(le.toLDAPResult());
}

// Make sure that we can use the connection to interact with the server.
RootDSE rootDSE = connection.getRootDSE();
</pre>

              <p></p>
              <h3>The "Who Am I?" Extended Operation</h3>

              <p>
                The "Who Am I?" extended operation is defined in RFC 4532, and is similar to the
                authorization identity controls in that it can be used to obtain the current
                authorization identity for a client connection.  The "Who Am I?" request, however,
                can be used at any time whereas the authorization identity controls can only be
                used in conjunction with a bind operation.
              </p>

              <p>
                The following code illustrates the use of the "Who Am I?" extended operation:
              </p>

              <pre>
// Use the "Who Am I?" extended request to determine the identity of the
// currently-authenticated user.
WhoAmIExtendedResult whoAmIResult;
try
{
  whoAmIResult = (WhoAmIExtendedResult)
       connection.processExtendedOperation(new WhoAmIExtendedRequest());
  // This doesn't necessarily mean that the operation was successful, since
  // some kinds of extended operations return non-success results under
  // normal conditions.
}
catch (LDAPException le)
{
  // For an extended operation, this generally means that a problem was
  // encountered while trying to send the request or read the result.
  whoAmIResult =
       new WhoAmIExtendedResult(new ExtendedResult(le.toLDAPResult()));
}

LDAPTestUtils.assertResultCodeEquals(whoAmIResult, ResultCode.SUCCESS);
String authzID = whoAmIResult.getAuthorizationID();
if (authzID.equals("") || authzID.equals("dn:"))
{
  // The user is authenticated anonymously.
}
else if (authzID.startsWith("dn:"))
{
  // The DN of the authenticated user should be authzID.substring(3)
}
else if (authzID.startsWith("u:"))
{
  // The username of the authenticated user should be authzID.substring(2)
}
else
{
  // The authorization ID isn't in any recognizable format.  Perhaps it's
  // a raw DN or a username?
}
</pre>
